﻿using System.Linq;
using Super_Management_Mayhem.Screens.Playing.Items;
using Transformable_Engine_v2.Engine.GameObjects.Primitives;
using Transformable_Engine_v2.Engine.Graphics;
using Transformable_Engine_v2.Engine.Helper;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Super_Management_Mayhem.Screens.Playing.Players.Manager
{
    public partial class Manager
    {
        private TE_Rectangle _downItemBoundingBox;
        private TE_Rectangle _leftItemBoundingBox;
        private TE_Rectangle _rightItemBoundingBox;
        private TE_Rectangle _upItemBoundingBox;

        /// <summary>
        /// Get the item collision box
        /// It is used to determine if an item is pickupable from the player's current location
        /// </summary>
        public TE_Rectangle ItemBoundingBox
        {
            get
            {
                if(_isCarrying)
                    return null;

                switch (_latestDirection)
                {
                    case Direction.Down:
                        return _downItemBoundingBox + _player.Position;
                    case Direction.Up:
                        return _upItemBoundingBox + _player.Position;
                    case Direction.Left:
                        return _leftItemBoundingBox + _player.Position;
                    case Direction.Right:
                        return _rightItemBoundingBox + _player.Position;
                }

                return null;
            }
        }

        public void InitializeCollisionObjects()
        {
            _leftItemBoundingBox = new TE_Rectangle(-1, -1, 0.5f, 1).ToGridBound();
            _rightItemBoundingBox = new TE_Rectangle(0.5f, -1, 0.5f, 1).ToGridBound();
            _upItemBoundingBox = new TE_Rectangle(-0.5f, -1.5f, 1, 0.5f).ToGridBound();
            _downItemBoundingBox = new TE_Rectangle(-0.5f, 0, 1, 0.5f).ToGridBound();

            if(Playscreen.SHOW_COLLISION)
            {
                _player.AddChildren(new RectanglePrimitive {
                                                               Shape = _leftItemBoundingBox.AsGridBoundRectangle(),
                                                               FillColor = new Color(Color.DarkKhaki, 100)
                                                           });

                _player.AddChildren(new RectanglePrimitive {
                                                               Shape = _rightItemBoundingBox.AsGridBoundRectangle(),
                                                               FillColor = new Color(Color.DarkKhaki, 100)
                                                           });

                _player.AddChildren(new RectanglePrimitive {
                                                               Shape = _upItemBoundingBox.AsGridBoundRectangle(),
                                                               FillColor = new Color(Color.DarkKhaki, 100)
                                                           });

                _player.AddChildren(new RectanglePrimitive {
                                                               Shape = _downItemBoundingBox.AsGridBoundRectangle(),
                                                               FillColor = new Color(Color.DarkKhaki, 100)
                                                           });
            }
        }

        private void HandleMovement(TE_Vector2 movementOffset,
                                    bool applyMovement = true)
        {
            MoveAndHandleCollision(movementOffset, applyMovement);
            bool hasWarped = HandleWarpCollision();
            CalculateCameraPosition(hasWarped, null);
            if(HandleHoleCollision())
                ChangeState(PlayerState.Fall);

            if (_currentPlayerState != PlayerState.Hurt && _currentPlayerState != PlayerState.Fall)
            {
                foreach (var collectible in Playscreen.Map.Collectibles())
                {
                    if (CollisionHelper.Intersects(collectible.GetBoundingBoxCollect(), BoundingBoxCollect))
                    {
                        collectible.Collect(_statistics);
                    }
                }
            }
        }

        private bool HandleHoleCollision()
        {
            foreach (var hole in Playscreen.Map.GetHoles())
            {
                if(CollisionHelper.Intersects(hole, _player.Position))
                {
                    _fallDirection = hole.CenterMiddle.Offset(0, 16);
                    _hole = new TE_Rectangle(hole);
                    return true;
                }
            }
            return false;
        }

        private bool HandleWarpCollision()
        {
            foreach (Warp warp in Playscreen.Map.GetWarp().Where(warp => CollisionHelper.Intersects(warp.BoundingBox, _player.Position))) {
                _player.Position = warp.WarpPlayer().Offset(8, 8);
                return true;
            }

            return false;
        }

        private void MoveAndHandleCollision(TE_Vector2 movementOffset,
                                            bool applyMovement)
        {
            TE_Rectangle oldBounding;
            TE_Rectangle newBounding;
            if (applyMovement)
            {
                oldBounding = new TE_Rectangle(BoundingBoxWall.Position, BoundingBoxWall.Size);
                newBounding = new TE_Rectangle(movementOffset + BoundingBoxWall.Position, BoundingBoxWall.Size);
            }
            else
            {
                oldBounding = new TE_Rectangle(_player.OldPosition + _boundingBoxWall.Position, BoundingBoxWall.Size);
                newBounding = new TE_Rectangle(BoundingBoxWall.Position, BoundingBoxWall.Size);
            }

            TE_Vector2 velocity = newBounding.Position - oldBounding.Position;
            TE_Vector2 normal;
            TE_Vector2 collisionOffset = Playscreen.Map.ResolveCollision(oldBounding, newBounding, velocity, out normal);

            if (collisionOffset == null)
            {
                _player.Position = newBounding.Position - _boundingBoxWall.Position;
            }
            else
            {
                _player.Position = collisionOffset - _boundingBoxWall.Position;
            }
        }
    }
}
